﻿#pragma once

#include <learn/geom/geom_nonbasis.h>

#include <functional>

namespace xi
{

namespace geom
{

template <std::size_t N> class Geom_ParamCurve : public Geom_NonbasisCurve<N>
{
    using Vec = VecT<N, double>;

  public:
    Geom_ParamCurve(Geom_ParamCurve &&) = delete;

    /**
     * @brief 构造函数
     *
     * @param[in] first
     * @param[in] last
     * @param[in] f
     * @param[in] df
     * @param[in] ddf
     * @param[in] dddf
     */
    Geom_ParamCurve(double first, double last, std::function<Vec(double)> f, std::function<Vec(double)> df = nullptr,
                    std::function<Vec(double)> ddf = nullptr, std::function<Vec(double)> dddf = nullptr)
        : m_first(first), m_last(last), m_f(f), m_df(df), m_ddf(ddf), m_dddf(dddf)
    {
    }

    /**
     * @brief 计算曲线上点的位置
     *
     * @param[in] t
     * @return Vec
     */
    Vec d0(double t) const override
    {
        return m_f(t);
    }

    /**
     * @brief 计算曲线上点的位置和导数
     *
     * @param[in] t
     * @return std::array<Vec, 2>
     */
    std::array<Vec, 2> d1(double t) const override
    {
        return {m_f(t), m_df(t)};
    }

    /**
     * @brief 计算曲线上点的位置、导数和二阶导数
     *
     * @param[in] t
     * @return std::array<Vec, 3>
     */
    std::array<Vec, 3> d2(double t) const override
    {
        return {m_f(t), m_df(t), m_ddf(t)};
    }

    /**
     * @brief 计算曲线上点的位置、导数、二阶导数和三阶导数
     *
     * @param[in] t
     * @return std::array<Vec, 4>
     */
    std::array<Vec, 4> d3(double t) const override
    {
        return {m_f(t), m_df(t), m_ddf(t), m_dddf(t)};
    }

    /**
     * @brief 起始参数
     *
     * @return double
     */
    double first_param() const override
    {
        return m_first;
    }

    /**
     * @brief 终止参数
     *
     * @return double
     */
    double last_param() const override
    {
        return m_last;
    }

    /**
     * @brief 序列化
     *
     * @return utils::Json
     */
    utils::Json dump_json() const override
    {
        utils::Json json;
        json["type"] = "param_curve";
        json["first_param"] = m_first;
        json["last_param"] = m_last;
        return json;
    }

  protected:
    double m_first, m_last;
    std::function<Vec(double)> m_f, m_df, m_ddf, m_dddf;
};

} // namespace geom

} // namespace xi
